/*
  DOES NOT USE THE BUILT-IN DETECTION FUNCTIONALITY!!!

alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Microsoft Excel SxView heap overflow attempt"; flowbits:isset,file.xls; flow:to_client,established; content:"|B0 00|"; byte_test:2,>,44,0,relative,little; byte_test:2,<,8225,0,relative,little; byte_jump:2,0,relative,little; pcre:"/^[\xB1\xB4-\xB6\xC5\xF1]\x00/R"; metadata:policy security-ips drop, service http; reference:cve,2010-0821; reference:url,technet.microsoft.com/en-us/security/bulletin/MS10-038; classtype:attempted-user; sid:16662;)

 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */


#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

//#define DEBUG 1
#ifdef DEBUG
#define DEBUG_SO(code) code
#else
#define DEBUG_SO(code)
#endif

/* declare detection functions */
int rule16662eval(void *p);

/* declare rule data structures */
/* flowbits:isset "file.xls"; */
static FlowBitsInfo rule16662flowbits0 =
{
    "file.xls",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule16662option0 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule16662flowbits0
    }
};
/* flow:established, to_client; */
static FlowFlags rule16662flow1 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule16662option1 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule16662flow1
    }
};
#ifndef CONTENT_FAST_PATTERN
#define CONTENT_FAST_PATTERN 0
#endif
// content:"|B0 00|", depth 0, fast_pattern; 
static ContentInfo rule16662content2 = 
{
    (uint8_t *) "|B0 00|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED|CONTENT_RELATIVE, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule16662option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule16662content2
    }
};
/* byte_test:size 2, value 44, operator >, relative, endian little; */
static ByteData rule16662byte_test3 = 
{
    2, /* size */
    CHECK_GT, /* operator */
    44, /* value */
    0, /* offset */
    0, /*multiplier */
    BYTE_LITTLE_ENDIAN|CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED|EXTRACT_AS_BYTE /* flags */
};

static RuleOption rule16662option3 = 
{
    OPTION_TYPE_BYTE_TEST,
    {
        &rule16662byte_test3
    }
};

/* byte_test:size 2, value 8225, operator <, relative, endian little; */
static ByteData rule16662byte_test4 = 
{
    2, /* size */
    CHECK_LT, /* operator */
    8225, /* value */
    0, /* offset */
    0, /*multiplier */
    BYTE_LITTLE_ENDIAN|CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED|EXTRACT_AS_BYTE /* flags */
};

static RuleOption rule16662option4 = 
{
    OPTION_TYPE_BYTE_TEST,
    {
        &rule16662byte_test4
    }
};

/* byte_jump:size 2, relative, endian little; */
static ByteData rule16662byte_jump5 = 
{
    2, /* size */
    0, /* operator, byte_jump doesn't use operator! */
    0, /* value, byte_jump doesn't use value! */
    0, /* offset */
    0, /* multiplier */
    BYTE_LITTLE_ENDIAN|CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED|EXTRACT_AS_BYTE /* flags */
};

static RuleOption rule16662option5 = 
{
    OPTION_TYPE_BYTE_JUMP,
    {
        &rule16662byte_jump5
    }
};

// pcre:"^[\xB1\xB4-\xB6\xC5\xF1]\x00", relative;
static PCREInfo rule16662pcre6 =
{
    "^[\\xB1\\xB4-\\xB6\\xC5\\xF1]\\x00", /* pattern */
    NULL,                               /* holder for compiled pattern */
    NULL,                               /* holder for compiled pattern flags */
    0,     /* compile flags */
    CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED     /* content flags */
};

static RuleOption rule16662option6 =
{
    OPTION_TYPE_PCRE,
    {
        &rule16662pcre6
    }
};

/* references for sid 16662 */
/* reference: cve "2010-0821"; */
static RuleReference rule16662ref1 = 
{
    "cve", /* type */
    "2010-0821" /* value */
};

/* reference: url "technet.microsoft.com/en-us/security/bulletin/MS10-038"; */
static RuleReference rule16662ref2 = 
{
    "url", /* type */
    "technet.microsoft.com/en-us/security/bulletin/MS10-038" /* value */
};

static RuleReference *rule16662refs[] =
{
    &rule16662ref1,
    &rule16662ref2,
    NULL
};

/* metadata for sid 16662 */
/* metadata:service http, policy security-ips drop; */
static RuleMetaData rule16662service1 = 
{
    "service http"
};


//static RuleMetaData rule16662policy1 = 
//{
//    "policy security-ips drop"
//};

static RuleMetaData rule16662policy2 = 
{
    "policy max-detect-ips drop"
};

static RuleMetaData *rule16662metadata[] =
{
    &rule16662service1,
//    &rule16662policy1,
    &rule16662policy2,
    NULL
};

RuleOption *rule16662options[] =
{
    &rule16662option0,
    &rule16662option1,
    &rule16662option2,
    &rule16662option3,
    &rule16662option4,
    &rule16662option5,
    &rule16662option6,
    NULL
};

Rule rule16662 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       16662, /* sigid */
       11, /* revision */
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "FILE-OFFICE Microsoft Excel SxView heap overflow attempt",     /* message */
       rule16662refs /* ptr to references */
       ,rule16662metadata
   },
   rule16662options, /* ptr to rule options */
   &rule16662eval, /* DO NOT use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule16662eval(void *p) {
    const uint8_t *cursor_normal = 0, *end_of_payload;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *cursor_temp; 
    const uint8_t *cursor_detect;

    uint16_t rwFirst;
    uint16_t rwLast;
    uint16_t colFirst;
    uint16_t colLast;

    uint8_t  found_attack_condition; 

    if(sp == NULL)
        return RULE_NOMATCH;

    // flowbits:isset "file.xls";
    if (processFlowbits(p, rule16662options[0]->option_u.flowBit) <= 0) 
        return RULE_NOMATCH;

    // flow:established, to_client;
    if (checkFlow(p, rule16662options[1]->option_u.flowFlags) <= 0)
        return RULE_NOMATCH;

    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0)
        return RULE_NOMATCH;

    // search for SxView record type (0xB0)
    // content:"|B0 00|", depth 0, fast_pattern;
    while (contentMatch(p, rule16662options[2]->option_u.content, &cursor_normal) > 0) {

        found_attack_condition = 0;

        // To avoid false positives, check if SxView's size is at least 44
        // byte_test:size 2, value 44, operator >, relative, endian little;
        if (byteTest(p, rule16662options[3]->option_u.byte, cursor_normal) <=  0) 
            return RULE_NOMATCH;

        // To avoid false positives, check if the maximum record size value is 8224
        // byte_test:size 2, value 8225, operator <, relative, endian little;
        if (byteTest(p, rule16662options[4]->option_u.byte, cursor_normal) <= 0) 
            return RULE_NOMATCH;

        cursor_detect = cursor_normal; // cursor points to the SxView record header size field
        cursor_temp = cursor_normal;   // we need to save the current cursor position to search for the next SxView record if the following tests fail 

        // To avoid false positives, jump to the next record 
        // byte_jump:size 2, relative, endian little;
        if (byteJump(p, rule16662options[5]->option_u.byte, &cursor_temp) <= 0) 
            return RULE_NOMATCH;
       
        // Now we know there are at least 44 bytes after cursor_temp
        cursor_detect += 2;  // skip the record size field (2 bytes)

        rwFirst = read_little_16(cursor_detect);
        cursor_detect += 2;
        rwLast  = read_little_16(cursor_detect);
        cursor_detect += 2;

        DEBUG_SO(printf("rwFirst %04x rwLast %04x\n", rwFirst, rwLast);)

        if (rwFirst > rwLast || rwLast > 16383)
        {
            found_attack_condition = 1;
        }
        else
        {
            colFirst = read_little_16(cursor_detect);
            cursor_detect += 2;
            colLast  = read_little_16(cursor_detect);

            DEBUG_SO(printf("colFirst %04x colLast %04x\n", colFirst, colLast);)

            if (colFirst > colLast || colLast > 255)
                found_attack_condition = 1;
            else 
                continue;
        }

        // To avoid false positives, check if the next record type is either 
        // Sxvd (0xB1), SxIvd (0xB4), SXPI (0xB6), SXDI (0xC5), SXLI (0xB5), or SXEx (0xF1)
        // pcre:"^[\xB1\xB4-\xB6\xC5\xF1]\x00", relative;
        if (found_attack_condition && (pcreMatch(p, rule16662options[6]->option_u.pcre, &cursor_temp) > 0))
            return RULE_MATCH;
    }
       
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule16662,
    NULL
};
*/
